#include "ASScreenMgr.h"
#include "..\screen\ASScreen.h"
#include "..\tool\ASLog.h"

static as_screen_manager s_as_screen_stack;

static ASINT as_screen_stack_get_max_counts(void)
{
    return AS_MAX_SCREEN_COUNTS;
}

static ASINT as_screen_stack_get_cur_counts(void)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    return (stack_p->cur_idx + 1);
}

static ASINT as_screen_stack_if_empty(void)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();

    if(stack_p->cur_idx == -1)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

static ASINT as_screen_stack_if_full(void)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    ASINT max_counts = as_screen_stack_get_max_counts();

    if(stack_p->cur_idx == (max_counts - 1))
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

static as_ret as_new_and_push_screen(as_screen_type type)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    as_screen* screen_p = NULL;
    as_ret ret = AS_OK;
    as_printf("as_new_and_push_screen");

    if(stack_p->if_full() == TRUE)
    {
        ret = AS_STACK_FULL;
        return ret;
    }

    screen_p = as_screen_calloc(type);
    //as_printf("~~~~~screen_p[%x]", screen_p);

    if(screen_p == NULL)
    {
        ret = AS_MEMORY_NOT_ENOUGH;
        return ret;
    }

    as_reset_enable_flush();

    if(stack_p->cur_idx >= 0)
    {
        stack_p->screens[stack_p->cur_idx]->pause(stack_p->screens[stack_p->cur_idx]);
    }

    stack_p->screens[++stack_p->cur_idx] = screen_p;
    as_screen_init(screen_p, type);
    return ret;
}

static as_ret as_delete_and_pop_screen(void)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    as_screen* screen_p = NULL;
    as_ret ret = AS_OK;
    screen_p = stack_p->get_cur_screen();

    if(screen_p == NULL)
    {
        ret = AS_INVALID_PARAM;
        return ret;
    }

    //execute the deinit function of this screen firstly
    screen_p->deinit_hdlr(screen_p);
    as_free(screen_p);
    stack_p->screens[stack_p->cur_idx] = NULL;
    --stack_p->cur_idx;

    if(stack_p->cur_idx >= 0)
    {
        stack_p->screens[stack_p->cur_idx]->resume(stack_p->screens[stack_p->cur_idx]);
    }

    return ret;
}

static as_screen* as_get_cur_screen(void)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    as_screen* screen_p = NULL;

    if(stack_p->if_empty() == TRUE)
    {
        return screen_p;
    }

    screen_p = stack_p->screens[stack_p->cur_idx];
    return screen_p;
}

static as_ret as_clear_all_screens(void)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    ASINT cur_counts = stack_p->get_cur_counts();
    as_ret ret = AS_OK;
    as_screen* screen_p = ASNULL;

    while(cur_counts > 0)
    {
        screen_p = stack_p->get_cur_screen();
        screen_p->deinit_hdlr(screen_p);
        as_free(screen_p);
        stack_p->screens[stack_p->cur_idx] = NULL;
        --stack_p->cur_idx;
        cur_counts--;
    }

    return ret;
}

/*
 *	initialize an empty screen stack
 */
static void as_screen_stack_init(as_screen_manager* stack_p)
{
    as_log_ui("<ui>----as_screen_stack_init");
    /*initialize attributes*/
    stack_p->is_inited = 1;
    stack_p->cur_idx = -1;
    memset(stack_p->screens, 0, sizeof(stack_p->screens));
    /*initialize methods*/
    stack_p->if_empty = as_screen_stack_if_empty;
    stack_p->if_full = as_screen_stack_if_full;
    stack_p->get_max_counts = as_screen_stack_get_max_counts;
    stack_p->get_cur_counts = as_screen_stack_get_cur_counts;
    stack_p->new_and_push_screen = as_new_and_push_screen;
    stack_p->delete_and_pop_screen = as_delete_and_pop_screen;
    stack_p->get_cur_screen = as_get_cur_screen;
    stack_p->clear_all = as_clear_all_screens;
}

as_screen_manager* as_get_screen_stack_instance(void)
{
    as_screen_manager* stack_p = &s_as_screen_stack;
    //as_log("~~~as_get_screen_stack_instance");

    if(stack_p->is_inited == 0)
    {
        //init screen stack
        as_screen_stack_init(stack_p);
    }

    return stack_p;
}

void as_screen_repaint(as_screen* screen_p)
{
    ASINT i = 0;
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    ASINT cur_counts = stack_p->get_cur_counts();

    if(screen_p == NULL)
    {
        return;
    }

    for(i = 0; i < cur_counts; i++)
    {
        if(stack_p->screens[i] == screen_p)
        {
            break;
        }
    }

    if(i == cur_counts)
        return;

    if(stack_p->screens[i]->is_small_screen == FALSE)
    {
        stack_p->screens[i]->paint_hdlr(stack_p->screens[i]);
    }
    else
    {
        ASINT j = i - 1;
        ASINT k;

        while(stack_p->screens[j]->is_small_screen == TRUE && j > 0)
        {
            j--;
        }

        for(k = j; k <= i; k++)
        {
            stack_p->screens[k]->paint_hdlr(stack_p->screens[k]);
        }
    }
}

/************************************************************************/
/* following are functions for test                                     */
/************************************************************************/
#ifdef AS_TEST_SCREEN_STACK_ENABLE
void as_screen_stack_test_main(void)
{
    as_screen_manager* stack_p = as_get_screen_stack_instance();
    as_ret ret = AS_SCREEN_OK;
    ASINT result;
    as_screen* screen_p = NULL;
    result = stack_p->get_max_counts();
    result = stack_p->if_empty();
    screen_p = stack_p->get_cur_screen();
    ret = stack_p->new_and_push_screen();
    screen_p = stack_p->get_cur_screen();
    ret = stack_p->delete_and_pop_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    ret = stack_p->new_and_push_screen();
    result = stack_p->if_full();
    screen_p = stack_p->get_cur_screen();
    result = stack_p->get_cur_counts();
    ret = stack_p->clear_all();
}

#endif